package br.unicamp.ic.inf300.arena.modelo.vendas.servico.impl;

/**
 * Venda de Bilhetes Eletronicos para Espetaculos (Arena Entretenimento S.A.)
 * TransacaoVendaServico.java
 */

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.log4j.Logger;

import br.com.admcredito.pagtosonline.PagamentoOnlineFachada;
import br.unicamp.ic.inf300.arena.modelo.logistico.Assento;
import br.unicamp.ic.inf300.arena.modelo.vendas.Bilhete;
import br.unicamp.ic.inf300.arena.modelo.vendas.CartaoCredito;
import br.unicamp.ic.inf300.arena.modelo.vendas.Pagamento;
import br.unicamp.ic.inf300.arena.modelo.vendas.Venda;
import br.unicamp.ic.inf300.arena.modelo.vendas.servico.ITransacaoVendaServico;
import br.unicamp.ic.inf300.arena.persistencia.dao.IBilheteDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.IEventoDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.IPagamentoDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.IVendaBilheteDAO;
import br.unicamp.ic.inf300.framework.persistencia.DAOFactory;
import br.unicamp.ic.inf300.framework.util.DataUtil;

public class TransacaoVendaServico implements ITransacaoVendaServico  {
	private static Logger _logger = Logger.getLogger( TransacaoVendaServico.class.getName() );

	/**
	 * - Popula objetos que colaboram na realizacao de uma venda de bilhetes e efetiva transacao de
	 * venda na base de dados de maneira transacional.
	 * 
	 * - Calcula total a pagar.
	 * 
	 * - Efetua pagamento para Arena via modulo externo, Pagtos. online.
	 * 
	 * @param bilhetes
	 * @param pagamento
	 * 
	 * @return Venda
	 */
	public Venda efetivarTransacao(Collection<Bilhete> bilhetes,
			Pagamento pagamento) throws Exception {
		_logger.debug("\n [[[[[ efetivarTransacao() ]]]]]\n\n" );

		Venda venda = new Venda();
		double valorTotal = 0.0D;

		if (bilhetes == null || bilhetes.size() == 0) {
			throw new Exception("Nenhum bilhete identificado!");
		}

		_logger.debug("\n 1. popular Venda \n");		
		venda.setDataHora(DataUtil.obterDataCorrente());
		venda.setPagamento(pagamento);
		venda.setBilhetes(bilhetes);

		IVendaBilheteDAO daoVenda = null;
		daoVenda = (IVendaBilheteDAO) DAOFactory.getImpl(IVendaBilheteDAO.class);

		_logger.debug("\n 1.1 obterProximoNumeroProtocolo \n");
		venda.setNumProtocolo( daoVenda.obterProximoNumeroProtocolo() );

		_logger.debug("\n 2. adequar estado Bilhetes da venda \n");
		Assento assento = null;
		for(Bilhete bilhete: bilhetes) {
			bilhete.setVenda(venda);
			bilhete.setEstado(Bilhete.ESTADO_VENDIDO);

			//IMPL. PROVISORIA ENQTO NAO TEM A FUNCIONALIDADE MAPA DE ASSENTOS
			assento = new Assento();
			assento.setNumero(1);
			bilhete.setAssento(assento);

			valorTotal += bilhete.getValor();
		}
		_logger.debug("*** [VALOR TOTAL DA VENDA: " + valorTotal + " ]");

		// num. cartao fixo da conta contabil da Arena (conta contabil padrao para todas unid. negocio)
		String strNumCartaoBeneficiado = "1234567";

		// try catch block TRANSACIONAL - DAOFactory
		try {
			DAOFactory.beginPersistenceTransaction();

			// atualmente so aceita pagto. com cartao
			String strNumCartaoPagante = null;
			if (pagamento instanceof CartaoCredito) {
				strNumCartaoPagante = String
						.valueOf(((CartaoCredito) pagamento).getNumeroCartao());
			}

			_logger.debug("\n 3. efetuarPagamento: interage com modulo externo Pagtos. online \n");
			PagamentoOnlineFachada.getInstance().efetuarPagamento(
					strNumCartaoPagante, valorTotal, strNumCartaoBeneficiado,
					String.valueOf( venda.getNumProtocolo() ), false);

			_logger.debug("\n 4. atualizar qtdVagasLivres do Evento ou dos Eventos envolvidos \n");
			IEventoDAO daoEvento = null;
			daoEvento = (IEventoDAO) DAOFactory.getImpl(IEventoDAO.class);

			if (bilhetes != null) {
				Bilhete bilhete = null;				

				if (bilhetes.size() > 0) {
					//considerar todos os bilhetes p. um mesmo evento
					bilhete = ( (ArrayList<Bilhete>) bilhetes).get(0);

					long codEvento = bilhete.getEvento().getCodEvento();
					int  qtdVagasLivre = bilhete.getEvento().getQtdVagasLivre();

					daoEvento.atualizar(codEvento, (qtdVagasLivre - bilhetes.size()));
				}
			}

			_logger.debug("\n 5. obter chave primaria codpagto gerada para o pagamento gravado \n");
			IPagamentoDAO daoPagto = null;
			daoPagto = (IPagamentoDAO) DAOFactory.getImpl(IPagamentoDAO.class);

			int codPagto = daoPagto.obterCodPagto() + 1;

			pagamento.setCodpagto(codPagto);
			pagamento.setValor(valorTotal);

			_logger.debug("\n 5.1 persistir pagto \n");
			daoPagto.inserir((CartaoCredito) pagamento);

			_logger.debug("\n 6. persistir venda \n");
			daoVenda.inserir(venda.getDataHora(), codPagto);

			_logger.debug("\n 7. persistir bilhete(s) c/ estado atualizado \n");
			IBilheteDAO daoBilhete = null;
			daoBilhete = (IBilheteDAO) DAOFactory.getImpl(IBilheteDAO.class);

			for(Bilhete bilhete: bilhetes) {
				daoBilhete.insert(bilhete);
			}

			DAOFactory.commitPersistenceTransaction();

			//popula colecao bilhetes com os numeros de bilhetes gerados na persistencia da VENDA
			//realizada com sucesso
			try {
				Collection<Bilhete> bilhetesID = null;
				bilhetesID = daoBilhete.obterBilhetes( venda.getNumProtocolo() );

				if (bilhetesID != null) {
					venda.setBilhetes( bilhetesID );
				}
			} catch (RuntimeException e) {
				; //dados exibidos nao mostrarao o num. real dos bilhetes
			}

			_logger.debug("\n\n ***** VENDA EFETIVADA COM SUCESSO: " + venda.toString() + "\n\n");
		}
		catch (SQLException sqlErr) {
			DAOFactory.rollbackPersistenceTransaction();
			sqlErr.printStackTrace();
			throw new Exception( sqlErr.getMessage() );
		}
		catch (Exception err) {
			DAOFactory.rollbackPersistenceTransaction();
			err.printStackTrace();
			throw new Exception( err.getMessage() );			
		}
		return venda;
	}
}